import HcRender from "HcRender";
import { defaultAlt, errorMsg } from "utils/constant";
import { debounce } from "utils/debounce";
import { attr, css, off, on, text } from "utils/dom";
import { warn } from "utils/log";
import { throttle } from "utils/throttle";
import { isArray, isFunction, isString } from "utils/types"

const noop = () => { }

export default class HcPhotos {
  static defaultAlt: string = defaultAlt;

  // 当前索引
  index: number;
  // 旋转角度
  deg: number;
  render: HcRender
  /** 正在移动的元素 */
  $moveEl: HTMLElement;

  private defaultOptions: THCPhotosOptions = {
    start: 0,
    /** 缩放系数 */
    zoomFactor: 0.2,
    data: [],

    onLoad: noop,
    onError: noop,
    onChange: noop,
  }

  settings: THCPhotosOptions
  initOptions: THCPhotosOptions
  // 缩放值
  zoom: number = 1;

  constructor(render: HcRender, options: THCPhotosOptions) {
    if (!isArray(options.data)) {
      warn(errorMsg.optionsDataNotArray);
      options.data = [];
    }

    this.render = render;
    this.initOptions = options;

    this.render.initHcPhotos();
    this.initProps();
    this.initEvent()
    this.open();
  }

  reset(options: THCPhotosOptions) {
    this.initOptions = options;
    this.initProps();
    // this.initEvent()
    this.open();
    return this;
  }

  initProps() {
    this.settings = {
      ...this.defaultOptions,
      ...this.initOptions
    };

    let start = this.settings.start
    if (isNaN(start) || start >= this.settings.data.length || start < 0) {
      start = 0
    }
    this.index = start
    this.deg = 0
    this.settings.data.forEach((opt, i) => {
      if (isString(opt)) {
        this.settings.data[i] = {
          src: opt as string,
          alt: HcPhotos.defaultAlt + (i + 1)
        }
      }
    })
  }
  /** 初始化事件 */
  initEvent() {
    const r = this.render;

    off(r.$left, 'click')
    off(r.$right, 'click')

    on(r.$left, 'click', () => {
      this.prev()
    })
    on(r.$right, 'click', () => {
      this.next()
    })

    if (this.settings.data.length === 1) {
      r.hideLR()
    }

    this.initTopLeftCtrlEvent();
    this.initTopRightCtrlEvent();
    this.initWrapEvent();
  }

  initTopLeftCtrlEvent() {
    const r = this.render;

    off(r.$leftCtrl, 'click')

    const map = new WeakMap();
    map.set(r.$enlarge, () => {
      r.refreshWrap();
    });
    on(r.$leftCtrl, 'click', (e) => {
      cbFromMap(map, e.target || e.srcElement)(e);
    })
  }
  initTopRightCtrlEvent() {
    const r = this.render;

    off(r.$rightCtrl, 'click')

    const map = new WeakMap();
    map.set(r.$close, () => {
      this.close();
    });
    map.set(r.$refresh, () => {
      this.deg = 0;
      this.zoom = 1;

      r.refreshImg();
    });
    map.set(r.$rotateLeft, () => {
      this.rotate(true)
    });
    map.set(r.$rotateRight, () => {
      this.rotate(false)
    })
    map.set(r.$zoomIn, () => {
      this.scale(true)
    })
    map.set(r.$zoomOut, () => {
      this.scale(false)
    })
    on(r.$rightCtrl, 'click', (e) => {
      cbFromMap(map, e.target || e.srcElement)();
    })
  }

  /** 主要注册移动事件 */
  initWrapEvent() {
    const r = this.render;

    off(r.$html, 'keydown');
    off(r.$html, 'mousedown');
    off(r.$html, 'mousemove');
    off(r.$html, 'mouseup');

    on(r.$html, 'keydown', (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        this.close();
      }
    });

    on(r.$html, 'mousedown', (e) => {
      this.$moveEl = e.target as HTMLElement || e.srcElement as HTMLElement;
    });

    const moveMap = new WeakMap();
    moveMap.set(r.$imgShade, (e) => {
      r.move(r.$imgBox, e);
    })
    moveMap.set(r.$name, (e) => {
      r.move(r.$photosBody, e);
    })
    moveMap.set(r.$resize, (e) => {
      r.resize(e);
    });
    on(r.$html, 'mousemove', (e) => {
      if (this.$moveEl == null) {
        return;
      }

      cbFromMap(moveMap, this.$moveEl)(e);
    });

    on(r.$html, 'mouseup', (e) => {
      // if (this.$moveEl == null) {
      //   return;
      // }
      r.resetMove(this.$moveEl);
      this.$moveEl = null;
    });

  }

  currentImg() {
    return this.settings.data[this.index]
  }
  setImgSrc() {
    const r = this.render;
    this.deg = 0;
    this.zoom = 1;
    css(r.$imgBox, 'transition', null);
    r.resetImg();
    css(r.$imgBox, 'transition', 'transform 0.3s')
    r.beforeLoadImg()

    const data = this.settings.data;
    const imgObj = data[this.index];
    attr(r.$img, 'src', (imgObj as THCPhotosImg).src);
    text(r.$name, (imgObj as THCPhotosImg).alt + ' ' + (this.index + 1) + '/' + data.length);
  }

  goTo(index: number) {
    const len = this.settings.data.length
    if (index < 0) {
      index = len - 1
    }
    if (index >= len) {
      index = 0
    }
    this.index = index
    this.setImgSrc()
    this._onChange()
  }
  next() {
    this.goTo(this.index + 1)
  }
  prev() {
    this.goTo(this.index - 1)
  }
  open() {
    const r = this.render;

    on(r.$img, 'load', (e) => {
      this._onLoad(e)
    })
    on(r.$img, 'error', (e) => {
      this._onError(e)
    })
    this.setImgSrc()
    r.openHcPhotos(this.settings.data.length)
  }
  close() {
    this.render.closeHcPhotos()
  }
  /**
   * 旋转
   * @param {boolean} isLeft 是否左旋转
   */
  rotate(isLeft) {
    if (isLeft) {
      this.deg -= 90
    } else {
      this.deg += 90
    }
    this.render.rotate(this.deg)
  }
  /**
   * 放大
   * @param {boolean} isZoomIn 是否放大
   */
  scale(isZoomIn: boolean) {
    if (isZoomIn) {
      this.zoom += this.settings.zoomFactor;
    } else {
      this.zoom -= this.settings.zoomFactor;
    }
    this.render.scale(this.zoom);
  }

  /**
   * 事件
   */

  /** 图片加载完成 */
  _onLoad(e) {
    this.render.afterLoadImg(e)
    this.settings.onLoad(this.currentImg(), this.index, e)
  }
  /** 图片加载异常 */
  _onError(e) {
    this.settings.onError(this.currentImg(), this.index, e);
  }
  /** 上一张下一张 */
  _onChange() {
    this.settings.onChange(this.currentImg(), this.index, this.render.$photosBody);
  }
}

function cbFromMap(map: WeakMap<any, any>, key: any) {
  const cb = map.get(key);
  return isFunction(cb) ? cb : noop;
}